package com.firemoss.ui.blanket
{
	import flash.display.DisplayObjectContainer;
	import flash.events.Event;
	import flash.events.IEventDispatcher;
	
	import mx.core.UIComponent;
	import mx.effects.Effect;
	import mx.events.EffectEvent;
	import mx.events.MoveEvent;
	import mx.events.ResizeEvent;

	public class AbstractBlanketOverlay extends UIComponent implements IBlanketOverlay
	{
		// STATIC
		
		// PRIVATE PROPERTIES
		
		/**
		 * The "parent" container for the overlay. Determined by the containerLocator.
		 */
		private var container : DisplayObjectContainer
		
		/**
		 * Added to container?
		 */
		private var addedToDisplayList : Boolean = false
		
		// PROTECTED PROPERTIES
		
		// PUBLIC PROPERTIES
		
		private var _target : UIComponent
		/**
		 * The target of the overlay
		 */
		public function set target ( target : UIComponent ) : void
		{
			_target = target
		}
		public function get target () : UIComponent
		{
			return _target 
		}
		
		/**
		 * The strategy for finding what will contain the component.
		 */
		public var containerLocator : IBlanketDisplayObjectContainerLocator
		
		/**
		 * Effect played to show overlay
		 */
		public var showEffect : Effect
		
		/**
		 * Effect played to hide overlay
		 */
		public var hideEffect : Effect
		
		private var _newShowSource : IEventDispatcher
		private var _showSource : IEventDispatcher
		/**
		 * Source of an event that can show the overlay
		 */
		public function set showSource( value : IEventDispatcher ) : void
		{
			_newShowSource = value
			manageVisibilityListeners()
		}
		public function get showSource() : IEventDispatcher 
		{
			return _showSource
		}

		private var _newShowEvent : String
		private var _showEvent : String
		/**
		 * Event name on which to show the overlay
		 */
		public function set showEvent( value : String ) : void
		{
			_newShowEvent = value
			manageVisibilityListeners()
		}
		public function get showEvent() : String 
		{
			return _showEvent
		}
		
		private var _newHideSource : IEventDispatcher
		private var _hideSource : IEventDispatcher
		/**
		 * Source of an event that can hide the overlay
		 */
		public function set hideSource( value : IEventDispatcher ) : void
		{
			_newHideSource = value
			manageVisibilityListeners()
		}
		public function get hideSource() : IEventDispatcher 
		{
			return _hideSource
		}
		
		private var _newHideEvent : String
		private var _hideEvent : String
		/**
		 * Event name on which to hide the overlay
		 */
		public function set hideEvent( value : String ) : void
		{
			_newHideEvent = value
			manageVisibilityListeners()
		}
		public function get hideEvent() : String 
		{
			return _hideEvent
		}
		
		 
		// CONSTRUCTOR
		
		public function AbstractBlanketOverlay()
		{
			super()
			
			containerLocator = OverlayLocators.POPUP
		}
		
		// PRIVATE METHODS
		
		private function manageVisibilityListeners():void
		{
			if ( showSource && showEvent )
			{
				showSource.removeEventListener( showEvent, showEventDispatched )
			}
			
			if ( _newShowSource && _newShowEvent )
			{
				_showSource = _newShowSource
				_showEvent = _newShowEvent
				
				showSource.addEventListener( showEvent, showEventDispatched, false, 0, true )
			}
			
			if ( hideSource && hideEvent )
			{
				hideSource.removeEventListener( hideEvent, hideEventDispatched )
			}
			
			if ( _newHideSource && _newHideEvent )
			{
				_hideSource = _newHideSource
				_hideEvent = _newHideEvent
				
				hideSource.addEventListener( hideEvent, hideEventDispatched, false, 0, true )
			}
		}
		
		// UICOMPONENT LIFECYCLE
		
		override public function initialize():void
		{
			super.initialize()
			
			invalidatePosition()
		}
		
		// OVERLAY "LIFECYCLE"
		
		protected function invalidatePosition() : void
		{
			
		}
		
		// PUBLIC METHODS

		/**
		 * Add to the container's child list.
		 */
		public function show( immediately : Boolean = false ):IBlanketOverlay
		{
			if (!addedToDisplayList)
			{
				this.target = target
				
				if ( !container )
				{
					container = containerLocator.findDisplayObjectContainer( { target : target } )
				}
				
				if ( target is UIComponent )
				{
					target.addEventListener( MoveEvent.MOVE, positionInvalidationEventDispatched, false, 0, true )
					target.addEventListener( ResizeEvent.RESIZE, positionInvalidationEventDispatched, false, 0, true )
					target.addEventListener( Event.REMOVED_FROM_STAGE, targetRemovedFromStage, false, 0, true )
					
					if (target.owner)
					{
						target.owner.addEventListener( MoveEvent.MOVE, positionInvalidationEventDispatched, false, 0, true )
						target.owner.addEventListener( ResizeEvent.RESIZE, positionInvalidationEventDispatched, false, 0, true )
					}
					
				}
	
				container.addChild( this ) 
				
				invalidatePosition()
				
				addedToDisplayList = true
				
				if ( showEffect && !immediately )
				{
					if (hideEffect && hideEffect.isPlaying)
					{
						hideEffect.removeEventListener( EffectEvent.EFFECT_END, hideImpl )
						hideEffect.stop()
					}
					
					showEffect.play()
					trace("Playing show")
				}
			}
			
			visible = true
			
			return this;
		}
		
		/**
		 * Either invokes the hide effect, playing hideImpl on complete, or invoke hideImpl directly if not effect
		 */
		public function hide( immediately : Boolean = false ) : void
		{
			if ( !hideEffect || immediately )
			{
				hideImpl()
			}
			else
			{
				if (showEffect && showEffect.isPlaying)
				{
					showEffect.stop()
				}
				
				hideEffect.addEventListener( EffectEvent.EFFECT_END, hideImpl, false, 0, true )
				trace("Playing hide")
				hideEffect.play()
			}
		}
		
		/**
		 * Remove from the container's child list.  Override to cleanup!
		 */
		protected function hideImpl( event : Event = null ) : void
		{
			if ( hideEffect )
			{
				hideEffect.removeEventListener( EffectEvent.EFFECT_END, hideImpl )
			}
			
			if ( target && target is UIComponent )
			{
				target.removeEventListener( MoveEvent.MOVE, positionInvalidationEventDispatched )
				target.removeEventListener( ResizeEvent.RESIZE, positionInvalidationEventDispatched )
				target.removeEventListener( Event.REMOVED_FROM_STAGE, targetRemovedFromStage )
				
			}
			
			if ( container && container.contains( this ) )
			{
				container.removeChild( this )
			}
			
			addedToDisplayList = false
		}
		
		
		// EVENT LISTENERS
		
		protected function positionInvalidationEventDispatched( event : Event ):void
		{
			invalidatePosition()
		}
		
		protected function targetRemovedFromStage( event : Event ) : void
		{
			hide()
		}
		
		protected function showEventDispatched( event : Event ) : void
		{
			show()
		}

		protected function hideEventDispatched( event : Event ) : void
		{
			hide()
		}
		
	}
}